unit MMDBMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.DBGrids, Vcl.ComCtrls,
  Data.DB, Datasnap.DBClient, Data.Win.ADODB, Vcl.StdCtrls, Vcl.Mask,
  Vcl.DBCtrls, Vcl.ExtCtrls, MMDBRegistry, MMDBEngine, Vcl.Menus,
  System.Actions, Vcl.ActnList, Data.FMTBcd, Data.SqlExpr,
  Vcl.ImgList, ShellAPI, StrUtils, MidasLib, MemDS, DBAccess, Ora;

type TUserView = (vwNormal, vwExpanded);

type
  TMMDBMainFrm = class(TForm)
    tcDocTab: TTabControl;
    dbGrid: TDBGrid;
    dbDataSet: TClientDataSet;
    sbStatus: TStatusBar;
    dbClientDataSource: TDataSource;
    ADOConnection: TADOConnection;
    ADOQuery: TADOQuery;
    ADOSource: TDataSource;
    SaveDialog1: TSaveDialog;
    Memo1: TMemo;
    btnUpdate: TButton;
    MainMenu1: TMainMenu;
    mmFile: TMenuItem;
    mmPathSettings: TMenuItem;
    mmView: TMenuItem;
    mmExpandedView: TMenuItem;
    lblUpdateStatus: TLabel;
    pnlSearchTools: TPanel;
    edNumFilter: TEdit;
    Label1: TLabel;
    edTitleFilter: TEdit;
    Label2: TLabel;
    ActionList1: TActionList;
    ConfigPaths: TAction;
    ExpandView: TAction;
    edSearchAll: TEdit;
    Label3: TLabel;
    btnClear: TButton;
    ImageList1: TImageList;
    FontDialog1: TFontDialog;
    ChangeGridFont1: TMenuItem;
    ChgGridFont: TAction;
    OraDataSource1: TOraDataSource;
    OraQuery: TOraQuery;
    lblLoopIt: TLabel;
    lblDocListCnt: TLabel;
    lblDataSetCnt: TLabel;
    Label4: TLabel;
    dsDocList: TClientDataSet;
    OraSession: TOraSession;
    exportCsv: TAction;
    ExportCSVFile1: TMenuItem;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnUpdateClick(Sender: TObject);
    procedure ProcessActiveTab;
    procedure tcDocTabChange(Sender: TObject);
    procedure ConfigureView(view: TUserView);
    procedure ExpandViewExecute(Sender: TObject);
    procedure edNumFilterChange(Sender: TObject);
    procedure edTitleFilterChange(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure edSearchAllChange(Sender: TObject);
    procedure dbGridDrawColumnCell(Sender: TObject; const Rect: TRect;
              DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure dbGridMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DisplayFileError(err: Integer);
    procedure FixDBGridColumnsWidth(const DBGrid: TDBGrid);
    procedure FormResize(Sender: TObject);
    procedure edSearchAllEnter(Sender: TObject);
    procedure ChgGridFontExecute(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure EliminateLowerRevs(var db: TClientDataSet; dt:TDocType);
    procedure pnlSearchToolsClick(Sender: TObject);
    procedure exportCsvExecute(Sender: TObject);
private
    { Private declarations }
  public
    { Public declarations }
    reg: TdbReg;
    ActiveTab: string;
  end;

var
  MMDBMainFrm: TMMDBMainFrm;

implementation

{$R *.dfm}


(***************************************************************************
Button1Click(): Test purposes- load data and compare
*******************************************************************************)
procedure TMMDBMainFrm.Button1Click(Sender: TObject);
begin
  try
     dbDataSet.SaveToFile(reg.NetCDSPath+'\MMDBV2_1DataFile.cds');
  except
    showmessage('Unable to save to '+reg.NetCDSPath);

  end;
end;

(***************************************************************************
btnUpdateClick: Exectued when update button is clicked (in expanded view). Sends
                SQL ADOQuery to Oracle to pull the most recent list of docs, then
                pulls actual doc paths from doc control and finds matches. Data is
                then placed in local client data set for usage by user.
*******************************************************************************)
procedure TMMDBMainFrm.btnUpdateClick(Sender: TObject);
var
  DocList: TStringList;
  errLog, tmpVal: string;
  i: Integer;
  docIdx: TDocType;
  Rec: TSearchRec;
begin
  dbClientDataSource.Enabled := False;   //disable during updates.
  DocList := TStringList.Create;
  dsDocList.CreateDataSet;      //create a temp data set to use in this function
  dsDocList.Open;
  if dsDocList.Active then
    Memo1.Lines.Add('dsDocList is active.')
      else
        Memo1.Lines.Add('dsDocList not active');
  try
    //ADOConnection.Open('MM','merit');
    OraSession.Connect;   //try to connect to server
    if OraSession.Connected then
       Memo1.Lines.Add('Connection to Oracle opened.');
  except
    ShowMessage('Unable to connect to Oracle database.');
    exit;
  end;
  try
    if not dbDataSet.Active then
      dbDataSet.Open;
    Memo1.Lines.Add('dbDataSet successfully opened.');
    dbDataSet.Filtered := False;
  except
    ShowMessage('Unable to open dbDataSet.');
    exit;
  end;
  if dbDataSet.RecordCount > 0 then
    dbDataSet.EmptyDataSet;
  for docIdx := Low(TDocType) to High(TDocType) do
    begin
      Application.ProcessMessages;
      //First, get the most current doc list from Oracle for each document type
      if not OraSession.Connected then
        begin
          ShowMessage('OraSession not connected to Oracle.');
          exit;
        end;
      try
        Memo1.Lines.Add('Updating '+ ExtractDocType(docIdx) +
                                   ' doc list from Oracle...' ) ;
        sbStatus.Panels[1].Text := 'Updating '+ ExtractDocType(docIdx) +
                                   ' doc list from Oracle...';
        OraQuery.SQL.Clear;  //Make sure previous string is not present.
        //Prepare SQL query for doc num, rev, and title, cycling through
        //each doc type.
        if docIdx <> eKIT then
          begin
            OraQuery.SQL.Add('SELECT ALL APPS.MM_DOCUMENTS.DOC_NUMBER,');
            OraQuery.SQL.Add('APPS.MM_DOCUMENTS.REV, APPS.MM_DOCUMENTS.TITLE');
            OraQuery.SQL.Add('FROM APPS.MM_DOCUMENTS WHERE (APPS.MM_DOCUMENTS.DOC_TYPE=');
            OraQuery.SQL.Add(#39+ExtractDocType(docIdx)+#39);
            OraQuery.SQL.Add('AND APPS.MM_DOCUMENTS.REV<>''OBS''');
            OraQuery.SQL.Add('AND APPS.MM_DOCUMENTS.REV<>''0''');
            OraQuery.SQL.Add('AND APPS.MM_DOCUMENTS.TITLE IS NOT NULL)');
            {OraQuery.SQL.Add('SELECT ALL DOC_TYPE, DOC_NUMBER, REV, TITLE FROM');
            OraQuery.SQL.Add(' (SELECT DOC_TYPE, DOC_NUMBER, REV, TITLE, MAX(REV)');
            OraQuery.SQL.Add('OVER(PARTITION BY DOC_NUMBER) AS MAXREV FROM APPS.MM_DOCUMENTS)');
            OraQuery.SQL.Add(' WHERE (DOC_TYPE=');
            OraQuery.SQL.Add(#39+ExtractDocType(docIdx)+#39);
            OraQuery.SQL.Add(' AND REV = MAXREV AND REV <> ''OBS'')'); }
          end
          else
            begin
              OraQuery.SQL.Add('SELECT SEGMENT1,DESCRIPTION,REVISION FROM');
              OraQuery.SQL.Add('(SELECT MTL_SYSTEM_ITEMS_B.SEGMENT1,MTL_SYSTEM_ITEMS_B.DESCRIPTION,');
              OraQuery.SQL.Add(' MTL_ITEM_REVISIONS_B.REVISION, MAX(REVISION) OVER(PARTITION BY SEGMENT1)');
              OraQuery.SQL.Add(' AS DINGUS FROM (MTL_SYSTEM_ITEMS_B INNER JOIN MTL_ITEM_REVISIONS_B ON');
              OraQuery.SQL.Add(' (MTL_SYSTEM_ITEMS_B.ORGANIZATION_ID = MTL_ITEM_REVISIONS_B.ORGANIZATION_ID)');
              OraQuery.SQL.Add(' AND (MTL_SYSTEM_ITEMS_B.INVENTORY_ITEM_ID = MTL_ITEM_REVISIONS_B.INVENTORY_ITEM_ID)))');
              OraQuery.SQL.Add('WHERE SEGMENT1 LIKE ''DK%'' AND REVISION = DINGUS');
            end;
         OraQuery.Open;  //execute the query.
         Memo1.Lines.Add('Successfully executed Query.');
         Memo1.Lines.Add('Transferring Query to client data set... ');
        OraQuery.First;  //ensure at first record
       if docIdx <> eKIT then
         begin       //Document not a kit, use standard Table field names
          while not OraQuery.Eof do
            begin
              if OraQuery.FieldByName('TITLE').AsString <> '' then
                begin
                  dbDataSet.AppendRecord([
                  OraQuery.FieldByName('DOC_NUMBER').AsString,
                  OraQuery.FieldByName('REV').AsString,
                  OraQuery.FieldByName('TITLE').AsString, '', '',   //dbcShortcut and dbcPath fields leftblank
                  OraQuery.FieldByName('DOC_NUMBER').AsString +     //combining doc num and rev here.
                  OraQuery.FieldByName('REV').AsString,
                  ExtractDocType(docIdx)]);
                end;
              OraQuery.Next;
              if OraQuery.RecNo mod 100 = 0 then
                Memo1.Lines[Memo1.Lines.count-1] := Memo1.Lines[Memo1.Lines.count-1] + '.';
               // Memo1.Lines.Add(OraQuery.FieldByName('DOC_NUMBER').AsString +     //combining doc num and rev here.
                  //OraQuery.FieldByName('REV').AsString);
            end;
        end
        else    //Document is a Kit, Field Names are different
          begin
            while not OraQuery.Eof do
            begin
              if OraQuery.FieldByName('DESCRIPTION').AsString <> '' then
                begin
                  dbDataSet.AppendRecord([
                  OraQuery.FieldByName('SEGMENT1').AsString,    //don't want to copy "D" at 1st of file name.
                  OraQuery.FieldByName('REVISION').AsString,
                  OraQuery.FieldByName('DESCRIPTION').AsString, '', '', '',   //dbcShortcut, dbcPath fields and dbcDocNumRev leftblank
                  ExtractDocType(docIdx)]);
                end;
              OraQuery.Next;
            end;   //end while
            (*The following code gets rid of the "-" character in the doc number*)
            dbDataSet.Filter :='dbcDocType = ''DK''';
            dbDataSet.Filtered  := True;
            dbDataSet.First;
            while not dbDataSet.Eof do
              begin
                tmpVal := copy(dbDataSet.FieldByName('dbcDocNum').AsString,2,3) +
                          copy(dbDataSet.FieldByName('dbcDocNum').AsString,6,
                          length(dbDataSet.FieldByName('dbcDocNum').AsString));
                dbDataSet.Edit;   //put into edit mode.
                dbDataSet['dbcDocNum'] := tmpVal;
                dbDataSet['dbcDocNumRev'] := tmpVal;  //Rev not recorded in DC Kits names.
                if dbDataSet.RecNo mod 100 = 0 then
                Memo1.Lines[Memo1.Lines.count-1] := Memo1.Lines[Memo1.Lines.count-1] + '.';
                //Memo1.Lines.Add(dbDataSet.FieldByName('dbcDocNum').AsString);
                dbDataSet.Next;
              end;

          end;  //end else and TRY block.
      except
        ShowMessage('Irrecoverable Error encountered while executing' + #13+
                    ' Oracle query.');
        exit;
      end;
      //Now that the client ds contains the proper doc list for the current doc type,
      //obtain a list of doc paths from the doc control drive, and match them up with
      // the docs in the data set. Remove any superfluous records.
      try
        //DocList.Clear;
        sbStatus.Panels[1].Text := 'Updating '+ ExtractDocType(docIdx) +
                                   ' document list...';
        if docIdx <> eKIT then
           GetDocPaths(docIdx, dsDocList, reg.DocCtrlPath, Memo1)
           else
             GetDocPaths(docIdx, dsDocList, reg.KitsPath, Memo1);    //only kits have different root.
        Memo1.Lines.Add('Document list contains '+IntToStr(dsDocList.RecordCount) +
                        ' '+ ExtractDocType(docIdx)+' documents.');
      except
        ShowMessage('Error encountered while reading from Doc Control.');
      end;

    MatchDocToPath(dbDataSet, dsDocList, Memo1, docIdx);
    try
      dbDataSet.SaveToFile(reg.LocalCDSPath+'\MMDBV2_1DataFile.cds');
    except
      ShowMessage('Unable to save local data File.');
    end;
  end;  //end for loop
  try
      dbDataSet.SaveToFile(reg.NetCDSPath + '\MMDBV2_1DataFile.cds');
  except
      ShowMessage('Unable to save data file to network location '+ reg.NetCDSPath);
  end;
  Memo1.Lines.Add('Document list complete.');
  sbStatus.Panels[0].Text := 'Total Doc Count: '+IntToStr(Memo1.Lines.Count);
  sbStatus.Panels[1].Text := 'Document lists complete.';
  DocList.Free;
  dsDocList.Close;
  //ADOConnection.Close;    //Can now disconnect from Oracle.
  OraSession.Close;
  dbDataSet.Filtered := True; //reapply filter.
  dbClientDataSource.Enabled := True;  //now display the data.
end;

(***************************************************************************
ChgGridFontExecute(): Allows the user to change the font displayed in the doc grid.
*******************************************************************************)
procedure TMMDBMainFrm.ChgGridFontExecute(Sender: TObject);
begin
  FontDialog1.Font := dbGrid.Font;   //preload settings
  if FontDialog1.Execute then
    begin
      dbGrid.Font := FontDialog1.Font;
      reg.Font := FontDialog1.Font;
      dbGrid.Refresh;

    end;
end;


(***************************************************************************
ConfigureView(): Configure the main form based on whether the view is normal, or
                 expanded view (where update controls are enabled);
*******************************************************************************)
procedure TMMDBMainFrm.ConfigureView(view: TUserView);
begin
  case view of
    vwNormal:
      begin
        lblUpdateStatus.Visible := False;
        Memo1.Visible := False;
        btnUpdate.Visible := False;
        pnlSearchTools.Top := 2;
        tcDocTab.Top := pnlSearchTools.Height + 10;
        tcDocTab.Height := tcDocTab.Height + Memo1.Height +15;
        lblDataSetCnt.Visible := False;
        lblDocListCnt.Visible := False;
        lblLoopIt.Visible := False;
        Label4.Visible := False;
      end;
    vwExpanded:
      begin
        lblUpdateStatus.Visible := True;
        Memo1.Visible := True;
        btnUpdate.Visible := True;
        Memo1.Top := 15;
        pnlSearchTools.Top := Memo1.Height + 20;
        tcDocTab.Top := Memo1.Height + pnlSearchTools.Height + 20;
        tcDocTab.Height := tcDocTab.Height - Memo1.Height -15;
        lblDataSetCnt.Visible := True;
        lblDocListCnt.Visible := True;
        Label4.Visible := True;
        lblLoopIt.Visible := True;
      end;
  end;
end;

(***************************************************************************
edbtnClear(): Clears all filter settings (except for current doc tab)
*******************************************************************************)
procedure TMMDBMainFrm.btnClearClick(Sender: TObject);
begin
  dbDataSet.Filter := 'dbcDocType = '+ QuotedStr(ActiveTab);
  edNumFilter.Text := '';
  edTitleFilter.Text := '';
  edSearchAll.Text := '';
end;

(***************************************************************************
edxxxExit(): Fires when relevant edit box is Entered. Need to reset
                   filter to doc setting.
*******************************************************************************)
procedure TMMDBMainFrm.edSearchAllEnter(Sender: TObject);
begin
  dbDataSet.Filter := 'dbcDocType = '+ QuotedStr(ActiveTab);
  edNumFilter.Text := '';
  edTitleFilter.Text := '';
  edSearchAll.Text := '';
end;

(***************************************************************************
edxxxFilterChange(): Fires when doc title filter edit box is changed. Progressively
                     filters data in active tab according to text.
*******************************************************************************)
procedure TMMDBMainFrm.edTitleFilterChange(Sender: TObject);
begin
  dbDataSet.FilterOptions := [foCaseInsensitive];
  dbDataSet.Filter := 'dbcDocType = '+ QuotedStr(ActiveTab)+ ' and '+
                      'dbcDocTitle LIKE '+ QuotedStr('%'+edTitleFilter.Text+'%');
end;
procedure TMMDBMainFrm.edSearchAllChange(Sender: TObject);
begin
  dbDataSet.FilterOptions := [foCaseInsensitive];
  dbDataSet.Filter := 'dbcDocType = '+ QuotedStr(ActiveTab)+ ' and '+
                      'dbcDocTitle LIKE '+ QuotedStr('%'+edSearchAll.Text+'%') +
                      ' OR dbcDocNum LIKE '+ QuotedStr('%'+edSearchAll.Text+'%');
end;
procedure TMMDBMainFrm.edNumFilterChange(Sender: TObject);
begin
  dbDataSet.FilterOptions := [foCaseInsensitive];
  dbDataSet.Filter := 'dbcDocType = '+ QuotedStr(ActiveTab)+ ' and '+
                      'dbcDocNum LIKE '+ QuotedStr('%'+edNumFilter.Text+'%');
end;

(******************************************************************************
EliminateLowerRevs(): Since all revisons of docs are stored, we only want the
                      most current revs when matching to files to elminate
                      unnecessary sorting/matching.
*******************************************************************************)
procedure TMMDBMainFrm.EliminateLowerRevs(var db: TClientDataSet; dt:TDocType);
var
  PreviousNum, PreviousRev, CurrentRow, NextRow: string;
begin
  db.First;
  db.Filter := 'dbcDocType = '+ QuotedStr(ExtractDocType(dt));
  db.Filtered := True;
  PreviousNum := db.FieldByName('dbcDocNum').AsString;
  PreviousRev := db.FieldByName('dbcDocRev').AsString;
  db.Next;
  while not db.Eof do
    begin
      if db.FieldByName('dbcDocNum').AsString = PreviousNum then      //Same doc number
        if db.FieldByName('dbcDocRev').AsString > PreviousRev then
          begin
            db.Prior;  //go back to previous record
            db.Delete;  //delete record.
            PreviousNum := db.FieldByName('dbcDocNum').AsString;
            PreviousRev := db.FieldByName('dbcDocRev').AsString;
          end
          else
            db.Delete;  //delete the current record.
      db.Next;
    end;
end;

(*************************************************************
ExpandViewExecute(): Exectued when "expand view" menu item is selected. Handles
                     menu appearance, then call routine to update the form view.
*******************************************************************************)
procedure TMMDBMainFrm.ExpandViewExecute(Sender: TObject);
begin
  if mmView.Checked then
    begin
      mmView.Checked := False;
      ConfigureView(vwNormal);
    end
    else
      begin
        mmView.Checked := True;
        ConfigureView(vwExpanded);
      end;
end;

(******************************************************************************
  exportCsv():  Generates a .csv file for use in a spreadsheet or text editor.
                Exports the current contents of the grid only.
*******************************************************************************)
procedure TMMDBMainFrm.exportCsvExecute(Sender: TObject);
var
  exportList: TStringList;
  i,j: Integer;
  tmp: string;
begin
  SaveDialog1.FileName := 'DocBrowser_Export'+ tcDocTab.Tabs[tcDocTab.TabIndex] + '.csv';
  if SaveDialog1.Execute then
    begin
      dbGrid.DataSource.Enabled := False;
      exportList := TStringList.Create;
      if dbGrid.DataSource.DataSet.RecordCount > 0 then
        begin
          exportList.Add('Doc Number, Doc Rev, Doc Title');
          dbGrid.DataSource.DataSet.First;
          while not dbGrid.DataSource.DataSet.Eof do
            begin
              tmp := '';
              for j := 0 to 2 do
                if j < 2 then
                  tmp := tmp + dbGrid.Columns[j].Field.AsString + ', '
                  else
                    tmp := tmp + dbGrid.Columns[j].Field.AsString;
              exportList.Add(tmp);
              dbGrid.DataSource.DataSet.Next;
            end;  //end while
          try
            exportList.SaveToFile(SaveDialog1.FileName);
          except
            ShowMessage('Unable to save file '+SaveDialog1.FileName);
          end;
           dbGrid.DataSource.DataSet.First;
      end;  //end if recordCount > 0
        exportList.Free;
        dbGrid.DataSource.Enabled := True;
    end;
end;

(***************************************************************************
FormClose(): Exectued  when the main form is closed
*******************************************************************************)

procedure TMMDBMainFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  try
    reg.RegSave;
  except
    ShowMessage('Unable to save changes to registry.');
  end;
end;

(***************************************************************************
FormCreate(): Exectued at start up when them main form is created.
*******************************************************************************)
procedure TMMDBMainFrm.FormCreate(Sender: TObject);
var
  err: string;
  out1, out2: TDateTime;
  LoadNewFile: Boolean;
begin
  try
    reg := TdbReg.Create;
    reg.Font := TFont.Create;
    reg.RegLoad;
  except
    ShowMessage('Unable to load regisitry values.');
  end;
  //Make sure application is not being exectued from public drive
  dbGrid.Font := reg.Font;
  //if ContainsText(ExtractFileDrive(Application.ExeName), ExtractFileDrive(reg.NetCDSPath)) then
  //  begin
  //    ShowMessage('DocBrowser application can not be ran from network drive.'+#13+
  //                'Please install on local drive and try again.');
  //    Application.Terminate;
  //  end;
  try
    LoadNewFile := False;
    if FileExists(reg.NetCDSPath+'\MMDBV2_1DataFile.cds', True) then        //first try to load master db file from network
      begin
         err := err+'1, ';
         if FileExists(reg.LocalCDSPath+'\MMDBV2_1DataFile.cds', False) then    //see if a local file also exists
           begin
             err := err+'2, ';
             FileAge(reg.NetCDSPath+'\MMDBV2_1DataFile.cds', out1, True);
             FileAge(reg.LocalCDSPath + '\MMDBV2_1DataFile.cds', out2, True);
             if out1-out2 > 1 then
               begin
                 err := err+'3, ';
                 LoadNewFile := True
               end
               else
                 begin
                   err := err+'4, ';
                   LoadNewFile := False;
                 end;
           end
           else
             begin
               err := err+'5, ';
               LoadNewFile := True;
             end;
     end;
    if LoadNewFile then
      begin
        err := err+'6, ';
        dbDataSet.LoadFromFile(reg.NetCDSPath+'\MMDBV2_1DataFile.cds');
        err := err+'a, ';
        dbDataSet.FileName := reg.NetCDSPath+'\MMDBV2_1DataFile.cds';
        err := err+'b, ';
        dbDataSet.SaveToFile(reg.LocalCDSPath+'\MMDBV2_1DataFile.cds');
        err := err+'c, ';
        dbDataSet.FileName := reg.LocalCDSPath+'\MMDBV2_1DataFile.cds';
        err := err+'d, ';
        sbStatus.Panels[1].Text := 'Master data file loaded and copied to local file.';
      end;
    if LoadNewFile = False then
      begin
       err := err+'7, ';
       if FileExists(reg.LocalCDSPath+'\MMDBV2_1DataFile.cds', False) then
        begin
          err := err+'8, ';
          dbDataSet.LoadFromFile(reg.LocalCDSPath+'\MMDBV2_1DataFile.cds');
          dbDataSet.FileName := reg.LocalCDSPath+'\MMDBV2_1DataFile.cds';
          sbStatus.Panels[1].Text := 'Using local data file. ';
        end
        else
          begin
             err := err+'9, ';
             sbStatus.Panels[1].Text := 'Unable to load network or local copy of data file. '+#13 +
                         'Application will now terminate.';
            reg.Free;
            Application.Terminate;
          end;
      end;
    FileAge(reg.LocalCDSPath + '\MMDBV2_1DataFile.cds', out2, True);
    err := err+'10, ';
    try
      sbStatus.Panels[2].Text := 'Data file last updated ' + DateTimeToStr(out2);
    except
      sbStatus.Panels[2].Text := '';
    end;
    //sbStatus.Panels[2].Text := 'Data file last updated ' + DateTimeToStr(out2);
    //err := err+'11, ';
  except
    ShowMessage('Unable to load network or local copy of data file. '+#13 +
                'Err value: '+ err + #13 +
                'Application will now terminate.');
    reg.Free;
    Application.Terminate;
  end;
  try
    dbDataSet.Active := True;
    dbClientDataSource.Enabled := True;
  except
    ShowMessage('Unable to open Client Data Set.');
  end;
  ConfigureView(vwNormal);
  //configure column widths to auto adjust
  dbGrid.Columns[4].Visible := False;
  dbGrid.Columns[5].Visible := False;
  dbDataSet.FieldByName('dbcDocTitle').Tag := 4 +
              Canvas.TextWidth(dbDataSet.FieldByName('dbcDocTitle').DisplayName);
  ProcessActiveTab;
end;

(***************************************************************************
KeyUp(): Fires when the key is released
*******************************************************************************)
procedure TMMDBMainFrm.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (Key = VK_F1) AND (Shift = [ssCtrl])  then
    mmExpandedView.Enabled := True;
end;

(***************************************************************************
FormResize(): Fires when the from is resized.
*******************************************************************************)
procedure TMMDBMainFrm.FormResize(Sender: TObject);
var
  fixOdd, val: Integer;
begin
  FixDBGridColumnsWidth(dbGrid);
  if odd(tcDocTab.Tabs.Count)  then
     fixOdd := 1
     else
       fixOdd := 0;
  val := 2 *((tcDocTab.Width-20) div (tcDocTab.Tabs.Count+fixOdd));
  tcDocTab.TabWidth := val;
end;

procedure TMMDBMainFrm.pnlSearchToolsClick(Sender: TObject);
begin

end;

(***************************************************************************
ProcessActiveTab(): Filters the document data in the master db file to show only
                    the document types based on the activce tab.
*******************************************************************************)
procedure TMMDBMainFrm.ProcessActiveTab;
var
  Filt: string;
begin
  dbDataSet.Filtered := False;
  case tcDocTab.TabIndex of
    _BLK:  Filt := 'BLK';
    _CRA: Filt := 'CRA';
    _CMS: Filt := 'CMS';
    _DEC: Filt := 'DEC';
    _DWG: Filt := 'DWG';
    _FMEA: Filt := 'FMEA';
    _FIX: Filt := 'F';
    _FORM: Filt := 'FRM';
    _GPS: Filt :=  'GPS';
    _KIT: Filt := 'DK';
    _MPS: Filt :=  'MPS';
    _PPS: Filt :=  'PPS';
    _PRO: Filt :=  'PRO';
    _QAP: Filt :=  'QAP';
    _QSP: Filt :=  'QSP';
    _REP: Filt :=  'RPT';
    _SP: Filt :=   'SP';
    //_STD: Filt := 'STD';
    _STP: Filt :=  'STP';
    _TBL: Filt :=  'TBL';
    _TEC: Filt := 'TEC';
    _TESTER: Filt := 'T';
    _TF: Filt := 'TF';
    _WS: Filt := 'WS';
  end;
  ActiveTab := Filt;
  dbDataSet.Filter := 'dbcDocType = ' + QuotedStr(Filt);
  dbDataSet.Filtered := True;
  dbGrid.Columns[0].Title.Caption := Filt + ' NUM';
  dbGrid.Columns[1].Title.Caption := Filt + ' REV';
  dbGrid.Columns[2].Title.Caption := Filt + ' TITLE';
  dbGrid.Columns[3].Title.Caption := 'LINK';
  edTitleFilter.Text := '';
  edNumFilter.Text := '';
  edSearchAll.Text := '';
  sbStatus.Panels[0].Text := Filt + ' Record Count: ' + IntToStr(dbDataSet.RecordCount);
  //FixDBGridColumnsWidth(dbGrid);
end;


(***************************************************************************
tcDocTabChange(): Fires when the user changes tabs
*******************************************************************************)
procedure TMMDBMainFrm.tcDocTabChange(Sender: TObject);
begin
  ProcessActiveTab;
end;

(***************************************************************************
dbGridDrawColumnCell(): Fires when a cell in the grid is redrawn. Used to
                        draw the icon for the doc extension type in the cell.
*******************************************************************************)
procedure TMMDBMainFrm.dbGridDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  bitmap : TBitmap;
  fixRect : TRect;
  bmpWidth : integer;
  imgIndex : integer;
  str: string;
begin
  fixRect := Rect;
  if Column.FieldName = 'dbcShortcut' then
  begin
    //adding some logic to grab the required image
    str := dbDataSet.FieldByName('dbcShortcut').AsString;
    if ContainsText(str, 'DOC') then imgIndex := 0
    else
    if ContainsText(str, 'XLS') then imgIndex := 1
    else
    if ContainsText(str, 'DWG') then imgIndex := 2
    else
       if ContainsText(str, 'SL') then imgIndex := 3
    else
       if ContainsText(str, 'PDF') then imgIndex := 4
    else
      if ContainsText(str, 'PPT') then imgIndex := 6
    else
      imgIndex := 5;    //default to folder image
    bitmap := TBitmap.Create;
    try
      ImageList1.GetBitmap(imgIndex,bitmap);
      //Fix the bitmap dimensions
      bmpWidth := (Rect.Bottom - Rect.Top);   //set bmp width = to row height.
      fixRect.Right := Rect.Left + bmpWidth;  //add space to the cell to fit the .bmp and the text
      //draw the bitmap
      dbGrid.Canvas.StretchDraw(fixRect,bitmap);
    finally
      bitmap.Free;
    end;
    // reset the output rectangle,
    // add space for the graphics
    fixRect := Rect;
    fixRect.Left := fixRect.Left + bmpWidth;
  end;
  //draw default text (fixed position)
  dbGrid.DefaultDrawColumnCell(fixRect, DataCol, Column, State);
end;

(******************************************************************************
dbGridMouseUp(): Fires when a cell in the grid is redrawn. Used to
                        draw the icon for the doc extension type in the cell.
*******************************************************************************)
procedure TMMDBMainFrm.dbGridMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  cell: TGridCoord;
  str, path: string;
  idx, err: Integer;
begin
  cell := dbGrid.MouseCoord(X,Y);
  if Button = mbLeft then
  begin
    if (cell.X = 4) and (cell.Y >= 1) then
     begin
      str := dbDataSet.FieldByName('dbcShortcut').AsString;
      Screen.Cursor := crHourGlass;
      if (ContainsText(str,'DOC')) or
         (ContainsText(str,'XLS')) or
         (ContainsText(str,'DWG')) or
         (ContainsText(str,'SL')) or
         (ContainsText(str,'PDF')) or
         (ContainsText(str,'PPT')) then
            begin
              err := ShellExecute(Handle, 'open', PChar(dbDataSet.FieldByName('dbcDocPath').AsString),
                                  nil,nil,SW_SHOWNORMAL);
              if err < 32 then
                DisplayFileError(err);
            end
         else
           begin
             path := dbDataSet.FieldByName('dbcDocPath').AsString;
             idx := Length(path)-1;
             while (path[idx] <> '\') and (idx > 0)do  //find the position of the right-most '\'.
               dec(idx);
             path := copy(path, 0, idx-1);
             ShellExecute(Handle, 'explore', PChar(path),
                          nil,nil,SW_SHOWNORMAL);
              if (err < 32) and (err > 0) then
                DisplayFileError(err);
           end;

     end;
  end;
   Screen.Cursor := crDefault;
   FixDBGridColumnsWidth(dbGrid);
end;

(******************************************************************************
DisplayFileError(): Called if an error occurs when a file or folder is attempted
                    to be opened from a link.
*******************************************************************************)
procedure TMMDBMainFrm.DisplayFileError(err: Integer);
var
  msg: string;
begin
  case err of
    0: msg := 'The operating system is out of memory or resources.';
    ERROR_FILE_NOT_FOUND: msg := 'The specified file was not found.';
    ERROR_PATH_NOT_FOUND: msg :='The specified path was not found.';
    ERROR_BAD_FORMAT: msg := 'The .exe file is invalid (does not have the correct internal format).';
    SE_ERR_ACCESSDENIED: msg := 'The operating system denied access to the specified file.';
    SE_ERR_ASSOCINCOMPLETE: msg := 'The file name association is incomplete or invalid.';
    SE_ERR_DDEBUSY: msg := 'A DDE transaction could not be completed because other DDE transactions were being processed.';
    SE_ERR_DDEFAIL: msg := 'A DDE transaction failed.';
    SE_ERR_DDETIMEOUT: msg := 'A DDE transaction could not be completed because the request timed out.';
    SE_ERR_DLLNOTFOUND: msg := 'A specified dynamic-link library was not found.';
    SE_ERR_NOASSOC: msg := 'There is no application associated with the given file name extension or TCustomFileRun attempted to print an unprintable file.';
    SE_ERR_OOM: msg := ' There was not enough memory to complete the operation.';
    SE_ERR_SHARE: msg := 'A sharing violation occurred';
  end;
  ShowMessage('The following error occured while opening the file or folder: '+#13 + msg);
end;

(******************************************************************************
dbGridMouseUp(): Automatically adjust width of columns according to test size
                 in the given column.
*******************************************************************************)
procedure TMMDBMainFrm.FixDBGridColumnsWidth(const DBGrid: TDBGrid);
var
  i : integer;
  TotWidth : integer;
  VarWidth : integer;
  ResizableColumnCount : integer;
  AColumn : TColumn;
begin
  //total width of all columns before resize
  TotWidth := 0;
  //how to divide any extra space in the grid
  VarWidth := 0;
  //how many columns need to be auto-resized
  ResizableColumnCount := 0;

  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
    TotWidth := TotWidth + DBGrid.Columns[i].Width;
    if DBGrid.Columns[i].Field.Tag <> 0 then
      Inc(ResizableColumnCount);
  end;

  //add 1px for the column separator line
  if dgColLines in DBGrid.Options then
    TotWidth := TotWidth + DBGrid.Columns.Count;

  //add indicator column width
  if dgIndicator in DBGrid.Options then
    TotWidth := TotWidth + IndicatorWidth;

  //width vale "left"
  VarWidth :=  DBGrid.ClientWidth - TotWidth;

  //Equally distribute VarWidth
  //to all auto-resizable columns
  if ResizableColumnCount > 0 then
    VarWidth := varWidth div ResizableColumnCount;

  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
    AColumn := DBGrid.Columns[i];
    if AColumn.Field.Tag <> 0 then
    begin
      AColumn.Width := AColumn.Width + VarWidth;
      if AColumn.Width < AColumn.Field.Tag then
        AColumn.Width := AColumn.Field.Tag;
    end;
  end;
  dbGrid.Columns[1].Width := dbGrid.Columns[1].Width +1;
end; (*FixDBGridColumnsWidth*)

end.
